﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting;
using System.Configuration;
using System.Threading;
using System.Collections;
using System.Runtime.Serialization.Formatters;
using CommonRemoting;
using ProtocoloCarSharing;

namespace ServidorCobroTiempoReal
{
    class Sistema
    {
        private static Sistema Instancia = null;
        private Tarifa tarifa;
        static MessageQueue queueReceptor;
        static MessageQueue queueEnvio;

        public static Sistema GetInstancia()
        {
            if (Instancia == null)
            {
                Instancia = new Sistema();
            }
            return Instancia;
        }

        private Sistema()
        {
            int tar = int.Parse((ConfigurationManager.AppSettings["tarifa"]));
            tarifa = new Tarifa(tar);
            IniciarRemoting();
            string nomMQServGestion = (ConfigurationManager.AppSettings["nomMSMQServGestion"]);

            string nomMQServCobro = (ConfigurationManager.AppSettings["nomMSMQServCobro"]);

            if (MessageQueue.Exists(nomMQServCobro))
            {
                queueReceptor = new MessageQueue(nomMQServCobro);
            }
            else
            {
                queueReceptor = MessageQueue.Create(nomMQServCobro);
            }
            queueReceptor.Formatter = new XmlMessageFormatter(new Type[] { typeof(MensajeProtocolo) });

            queueEnvio = new MessageQueue(nomMQServGestion);

            //ThreadPool.QueueUserWorkItem(new WaitCallback(EscucharMSMQ));
        }

        public MensajeProtocolo RealizarTarifa(MensajeProtocolo msj)
        {
            List<string> datos = msj.InfoDatos();
            int distancia;
            try{
                distancia = int.Parse(datos[4]);
            } catch (FormatException){
                distancia = 0;
            }
            string datosAEnviar = datos[0] + Protocolo.SEPARADOR + datos[1] + Protocolo.SEPARADOR + datos[2] + Protocolo.SEPARADOR + datos[3] +
                                 Protocolo.SEPARADOR + datos[4] + Protocolo.SEPARADOR + tarifa.ConsumoEnPlata(distancia) + Protocolo.SEPARADOR + DateTime.Now.ToString() + Protocolo.SEPARADOR + datos[5];
            MensajeProtocolo msjAEnviar = new MensajeProtocolo(Protocolo.Header.REQ, Protocolo.Comando.CONSUMO, datosAEnviar.Length, datosAEnviar);
            string id = EnviarConsumoMSMQ(msjAEnviar);
            Console.WriteLine("Se realizo factura y se envio msj a servidor de Gestion de Clientes : " + datosAEnviar);

            MensajeProtocolo msjARet = EscucharMSMQ(id);

            return msjARet;
        }

        private MensajeProtocolo EscucharMSMQ(string id)
        {
            try
            {
                TimeSpan ts = new TimeSpan(10000000);
                Message msg = queueReceptor.ReceiveByCorrelationId(id, ts);
                MensajeProtocolo msjRec = (MensajeProtocolo)msg.Body;
                return msjRec;
            }
            catch (MessageQueueException e)
            {
                return new MensajeProtocolo(Protocolo.Header.RES, Protocolo.Comando.SERVIDOR_FUERA_DE_SERVICIO, e.Message.Length, e.Message);
            }
        }

        private string EnviarConsumoMSMQ(MensajeProtocolo msj)
        {
            if (queueEnvio == null)
            {
                string nomMQServGestion = (ConfigurationManager.AppSettings["nomMSMQServGestion"]);
                queueEnvio = new MessageQueue(nomMQServGestion);
            }
            Message msgAEnviar = new Message(msj);
            queueEnvio.Send(msgAEnviar, "Consumo");
            return msgAEnviar.Id;
        }

        private void IniciarRemoting()
        {
            IDictionary props = new Hashtable();
            string puerto = (ConfigurationManager.AppSettings["puertoRemotig"]);
            props["port"] = puerto;
            props["name"] = "CanalServCobro";
            BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
            serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
            IChannel chan = new TcpChannel(props, null, serverProvider);
            ChannelServices.RegisterChannel(chan, false);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(ServCobroRemoting), "ServidorCobro", WellKnownObjectMode.SingleCall);
        }

    }
}
